#!/usr/bin/env bash

###############################################################
# File Name: install_kibana.sh
# Version: V1.0
# Author: Brian Hsiung
# Created Time : 2025-01-21 9:37:53
# Description: kibana部署脚本
##############################################################

# 调试跟踪（-e: 与错退出， -u: 捕获未定义的变量， -x: 调试模式，在执行每个命令前，将其打印到标准错误输出）
# set -eux

# 端口
declare -r KB_PORT="5601"
# 安装目录
declare -r KB_BASE="/data/kibana"
# 运行用户
declare -r KB_USER="elkuser"
# 版本
declare -r KB_VERSION="7.16.3"
# 软连接目录
declare -r KB_HOME="$KB_BASE/kibana"
# 日志目录
declare -r KB_LOG_DIR="$KB_HOME/logs"
# Elasticsearch用户名
declare -r ES_USERNAME="elastic"
# Elasticsearch密码
declare -r ES_PASSWORD="TawqcNpekz23wYrdAemL"
# 阿里云OSS存储地址
declare -r OSS_BASE_URL="https://brianhsiung.oss-cn-hangzhou.aliyuncs.com"
# Elasticsearch集群地址
ES_HOSTS=("172.26.85.159:9200" "172.26.85.160:9200" "172.26.85.161:9200")
# 生成带引号的数组
ES_HOSTS_STR=$(printf '"http://%s",' "${ES_HOSTS[@]}" | sed 's/,$//')

WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$WORK_DIR" || exit

### 日志函数
log_info()    { echo -e "\033[34m[INFO] $*\033[0m"; }
log_warn()    { echo -e "\033[33m[WARNING] $*\033[0m"; }
log_success() { echo -e "\033[32m[SUCCESS] $*\033[0m"; }
log_error()   { echo -e "\033[31m[ERROR] $*\033[0m"; exit 1; }

### 检查依赖
check_dependency() {
    local cmd=$1
    if ! command -v "$cmd" &>/dev/null; then
        log_error "依赖缺失: 请先安装 $cmd"
    fi
}

#############################################
# 设置目录权限（递归检查上级目录）
#############################################
set_parent_permissions() {
    ### 某些等保三服务器默认新建的的目录权限为700，文件权限为600，导致服务无法启动，所以需要遍历上级目录，将权限修改为755
    # 获取真实目录
    local target_dir
    target_dir=$(realpath "$1")
    # 获取上级目录
    local current_dir
    current_dir=$(dirname "$target_dir")

    # 做个判断，避免进入死循环
    [ -d "$target_dir" ] || log_error "目录不存在 [$target_dir]"

    # 排除敏感目录
    local -a exclude_dirs
    exclude_dirs=("/usr" "/usr/local" "/bin" "/sbin" "/lib" "/etc" "/dev" "/var" "/root" "/usr/share")

    while [[ "$current_dir" != "/" ]]; do

        # 排除敏感目录
        if printf '%s\n' "${exclude_dirs[@]}" | grep -qx "$current_dir"; then
            log_info "跳过系统保护目录: $current_dir"
            current_dir=$(dirname "$current_dir")
            continue
        fi

        # 跳过不存在的目录
        if [[ ! -d "$current_dir" ]]; then
            log_warn "警告: 目录不存在 [$current_dir]"
            current_dir=$(dirname "$current_dir")
            continue
        fi
        
        # 获取当前目录权限
        local perm_oct
        perm_oct=$(stat -c '%a' "$current_dir")
        log_info "目录 $current_dir 的原始权限为: $perm_oct"
        
        if [[ "$perm_oct" != "755" ]]; then
            log_info "正在设置权限: [755] -> $current_dir"
            if ! chmod 755 "$current_dir"; then
                log_error "错误: 无法设置目录权限 [$current_dir]"
            fi
        else
            log_success "权限正确 [755]: $current_dir"
        fi

        # 向上一级目录
        current_dir=$(dirname "$current_dir")
    done
}

install_kibana() {

    # 使用root账号执行脚本
    [[ "$(id -u)" -ne 0 ]] && log_error "请使用root用户执行此脚本"

    check_dependency "tar"
    check_dependency "groupadd"
    check_dependency "useradd"

    # 添加用户
    if ! getent group "$KB_USER" &>/dev/null; then
        log_info "创建用户组: $KB_USER"
        groupadd "$KB_USER"
    fi

    if ! getent passwd "$KB_USER" &>/dev/null; then
        log_info "创建用户: $KB_USER"
        useradd -g "$KB_USER" "$KB_USER"
    fi

    # 开放端口
    if ss -lntu | grep -q ":$KB_PORT " >/dev/null 2>&1; then
        log_error "端口冲突: 请检查端口 $KB_PORT 是否被占用"
    fi
    
    if systemctl is-active --quiet firewalld; then
        log_info "开放防火墙端口 $KB_PORT"
        firewall-cmd --zone=public --add-port="$KB_PORT"/tcp --permanent
        firewall-cmd --reload
    fi

    local cpu_type
    local kibana_pkg
    local oss_url
    
	arch=$(uname -m)    ## uname -m 在Redhat 和 Debian上均可执行， dpkg --print-architecture 只能在Debian上执行

	case "${arch}" in
		aarch64|arm64)
			cpu_type="aarch64"
			kibana_pkg="kibana-$KB_VERSION-linux-aarch64.tar.gz"
            oss_url="$OSS_BASE_URL/deploy/elastic/$cpu_type/$kibana_pkg"
			;;
		amd64|x86_64)
			cpu_type="x86_64"
			kibana_pkg="kibana-$KB_VERSION-linux-x86_64.tar.gz"
            oss_url="$OSS_BASE_URL/deploy/elastic/x64/$kibana_pkg"
			;;
		*)
			echo "不支持的CPU架构: $arch"
			exit 1
		;;
	esac

    if curl -sIfo /dev/null --connect-timeout 5 --max-time 10 "$OSS_BASE_URL"/health; then
        if [ ! -f "$kibana_pkg" ]; then
            log_info "使用在线安装模式，下载安装包: $kibana_pkg"
            check_dependency "wget"
            wget -q "$oss_url" || log_error "$kibana_pkg 下载失败"
        fi
    else
        log_info "使用离线安装模式"
    fi

    [ -f "$kibana_pkg" ] || log_error "当前目录无 $kibana_pkg"

    log_info "解压 $kibana_pkg 到 $KB_BASE"
    [ -d "$KB_BASE" ] || mkdir -p "$KB_BASE"
    tar -zxf "$kibana_pkg" -C "$KB_BASE" || log_error "解压失败"

    if [ -L "$KB_HOME" ]; then
        log_info "检测到旧软链接 $KB_HOME..."
        ln -sfn "$KB_HOME"-"$KB_VERSION"-linux-"$cpu_type" "$KB_HOME" || log_error "软链接更新失败"
    elif [ -e "$KB_HOME" ]; then
        log_error "$KB_HOME 已存在且不是软链接，请手动处理"
    else
        log_info "创建软链接 $KB_HOME"
        ln -s "$KB_HOME"-"$KB_VERSION"-linux-"$cpu_type" "$KB_HOME" || log_error "软链接创建失败"
    fi

    [ -d "$KB_LOG_DIR" ] || mkdir -p "$KB_LOG_DIR"

    chown "$KB_USER":"$KB_USER" -R "$KB_BASE"

    # 设置上级目录权限
    set_parent_permissions "$KB_BASE"

    # chown "$KB_USER":"$KB_USER" -R "$KB_HOME"
}

add_config() {
    # 在执行前，修改以下IP，以及Elasticsearch对应的地址与账号密码
    log_info "添加配置文件"
    cat > "$KB_HOME"/config/kibana.yml << EOF
server.port: $KB_PORT
# 当前主机IP，根据实际情况修改
server.host: "$(hostname -I|awk '{print $1}')"
server.name: "Kibana"
# elasticsearch地址，根据实际情况修改
elasticsearch.hosts: [$ES_HOSTS_STR]
# elasticsearch账号，根据实际情况修改
elasticsearch.username: "$ES_USERNAME"
# elasticsearch密码，根据实际情况修改
elasticsearch.password: "$ES_PASSWORD"
# 日志目录，根据实际情况修改
logging.dest: $KB_LOG_DIR/kibana.log
i18n.locale: "zh-CN"
EOF

}

add_service() {
    log_info "添加服务"
    cat > /usr/lib/systemd/system/kibana.service << EOF
[Unit]
Description=Kibana
Documentation=https://www.elastic.co/cn/kibana
After=network-online.target
Wants=network-online.target

[Service]
Type=simple

User=$KB_USER
Group=$KB_USER

ExecStart=/bin/bash -c "$KB_HOME/bin/kibana"

Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

    # 启动服务
    systemctl daemon-reload
    log_info "启动服务"
    systemctl enable --now kibana
    systemctl status kibana

}

main () {
    log_info "开始安装Kibana"
    
    install_kibana
    add_config
    add_service

    log_success "Kibana安装完成"
}

main